import { _decorator } from "cc";
import { CONTROLLER_ENUM, DIRECTION_ENUM, ENTITY_STATE_ENUM, ENTITY_TYPE_ENUM, EVENT_ENUM } from "../../Enums";
import EventManager from "../../Runtime/EventManager";
import { PlayerStateMachine } from "./PlayerStateMachine";
import { EntityManager } from "../../Base/EntityManager";
import DataManager from "../../Runtime/DataManager";
import { IEntity } from "../../Levels";
import { BurstManager } from "../Burst/BurstManager";

const { ccclass, property } = _decorator


@ccclass('PlayerManager')
export class PlayerManager extends EntityManager {
  targetX: number = 0
  targetY: number = 0
  isMoving = false
  private readonly speed = 1 / 10

  async init(params:IEntity) {
    this.fsm = this.addComponent(PlayerStateMachine)
    await this.fsm.init()
    super.init(params)
    this.targetX = this.x
    this.targetY = this.y

    EventManager.Instance.on(EVENT_ENUM.PLAYER_CTRL, this.inputHandle, this)
    EventManager.Instance.on(EVENT_ENUM.ATTACK_PLAYER, this.onDeath, this)
  }

  onDestroy() {
    EventManager.Instance.off(EVENT_ENUM.PLAYER_CTRL, this.inputHandle)
    EventManager.Instance.off(EVENT_ENUM.ATTACK_PLAYER, this.onDeath)
  }

  onDeath(type:ENTITY_STATE_ENUM) {
    console.log('state on death:', type)
    this.state = type
  }

  update() {
    this.updateXY()
    super.update()
  }

  updateXY() {
    if (this.targetX < this.x) {
      this.x -= this.speed
    } else if (this.targetX > this.x) {
      this.x += this.speed
    }
    if (this.targetY < this.y) {
      this.y -= this.speed
    } else if (this.targetY > this.y) {
      this.y += this.speed
    }
    if (Math.abs(this.targetX - this.x) <= 0.1 && Math.abs(this.targetY - this.y) <= 0.1 && this.isMoving) {
      this.isMoving = false
      this.x = this.targetX
      this.y = this.targetY
      EventManager.Instance.emit(EVENT_ENUM.PLAYER_MOVE_END)
    }
  }

  inputHandle(inputDirection: CONTROLLER_ENUM) {
    if (this.isMoving) {
      return
    }
    if (this.state === ENTITY_STATE_ENUM.DEATH || this.state === ENTITY_STATE_ENUM.AIRDEATH || this.state === ENTITY_STATE_ENUM.ATTACK) {
      return
    }

    const id = this.willAttack(inputDirection)
    if (id) {
      EventManager.Instance.emit(EVENT_ENUM.ATTACK_ENEMY, id)
      EventManager.Instance.emit(EVENT_ENUM.DOOR_OPEN)
      return
    }

    if (this.willBlock(inputDirection)) {
      EventManager.Instance.emit(EVENT_ENUM.SCREEN_SHAKE)
      return
    }
    this.move(inputDirection)
  }

  willAttack(type: CONTROLLER_ENUM) {
    const enemies = DataManager.Instance.enemies.filter(enemy => enemy.state !== ENTITY_STATE_ENUM.DEATH)
    for (let i = 0; i < enemies.length; i++) {
      const {x:enemyX, y:enemyY, id:enemyId} = enemies[i]
      if (type === CONTROLLER_ENUM.TOP && this.direction === DIRECTION_ENUM.TOP && enemyX === this.x && enemyY === this.targetY - 2) {
        this.state = ENTITY_STATE_ENUM.ATTACK
        return enemyId
      } else if (type === CONTROLLER_ENUM.LEFT && this.direction === DIRECTION_ENUM.LEFT && enemyX === this.x - 2 && enemyY === this.targetY) {
        this.state = ENTITY_STATE_ENUM.ATTACK
        return enemyId
      } else if (type === CONTROLLER_ENUM.BOTTOM && this.direction === DIRECTION_ENUM.BOTTOM && enemyX === this.x && enemyY === this.targetY + 2) {
        this.state = ENTITY_STATE_ENUM.ATTACK
        return enemyId
      } else if (type === CONTROLLER_ENUM.RIGHT && this.direction === DIRECTION_ENUM.RIGHT && enemyX === this.x + 2 && enemyY === this.targetY) {
        this.state = ENTITY_STATE_ENUM.ATTACK
        return enemyId
      }
    }
    return ''
  }

  willBlock(inputDirection: CONTROLLER_ENUM) {
    const {targetX:x, targetY:y, direction}  = this
    const {tileInfo} = DataManager.Instance
    const {x:doorX, y:doorY, state:doorState} = DataManager.Instance.door
    const enemies = DataManager.Instance.enemies.filter(enemy => enemy.state !== ENTITY_STATE_ENUM.DEATH)
    const bursts: BurstManager[] = DataManager.Instance.bursts.filter(burst => burst.state !== ENTITY_STATE_ENUM.DEATH)

    if (inputDirection === CONTROLLER_ENUM.TOP) {
      const playerNextY = y - 1
      if (direction === DIRECTION_ENUM.TOP) {
        const weaponNextY = y - 2
        // out of the map
        if (playerNextY < 0) {
          this.state = ENTITY_STATE_ENUM.BLOCKFRONT
          return true
        }

        const playerTile = tileInfo[x][playerNextY]
        const weaponTile = tileInfo[x][weaponNextY]

        // door block
        if (((x === doorX && playerNextY === doorY) || (x === doorX && weaponNextY === doorY)) && doorState !== ENTITY_STATE_ENUM.DEATH) {
          this.state = ENTITY_STATE_ENUM.BLOCKFRONT
          return true
        }

        // enemies block
        for (let i = 0; i < enemies.length; i++) {
          const { x:enemyX, y:enemyY } = enemies[i]
          if ((x === enemyX && playerNextY === enemyY) || (x === enemyX && weaponNextY === enemyY)) {
            this.state = ENTITY_STATE_ENUM.BLOCKFRONT
            return true
          }
        }

        // burst
        for(let i = 0; i < bursts.length; i++) {
          const {x:burstX, y:burstY} = bursts[i]
          // player move to burst tile and weapon can be turnable
          if ((x === burstX && playerNextY === burstY) && (!weaponTile || weaponTile.turnable)) {
            return false // can move
          }
        }

        if (playerTile && playerTile.moveable && (!weaponTile || weaponTile.turnable)){
          // player can move
        } else {
          this.state = ENTITY_STATE_ENUM.BLOCKFRONT
          return true
        }
      } else if(direction === DIRECTION_ENUM.BOTTOM) {
        if (playerNextY < 0) {
          this.state = ENTITY_STATE_ENUM.BLOCKBACK
          return true
        }
        const weaponNextY = y
        const playerTitle = tileInfo[x]?.[playerNextY]
        const weaponTitle = tileInfo[x]?.[weaponNextY]
        if (playerTitle && playerTitle.moveable && (!weaponTitle || weaponTitle.turnable)) {

        } else {
          this.state = ENTITY_STATE_ENUM.BLOCKBACK
          return true
        }
      } else if (direction === DIRECTION_ENUM.LEFT) {
        if (playerNextY < 0) {
          this.state = ENTITY_STATE_ENUM.BLOCKRIGHT
          return true
        }
        const weaponNextX = x - 1
        const weaponNextY = y - 1
        const playerTitle = tileInfo[x]?.[playerNextY]
        const weaponTitle = tileInfo[weaponNextX]?.[weaponNextY]
        if (playerTitle && playerTitle.moveable && (!weaponTitle || weaponTitle.turnable)) {

        } else {
          this.state = ENTITY_STATE_ENUM.BLOCKRIGHT
          return true
        }
      } else if (direction === DIRECTION_ENUM.RIGHT) {
        if (playerNextY < 0) {
          this.state = ENTITY_STATE_ENUM.BLOCKLEFT
          return true
        }
        const weaponNextX = x + 1
        const weaponNextY = y - 1
        const playerTitle = tileInfo[x]?.[playerNextY]
        const weaponTitle = tileInfo[weaponNextX]?.[weaponNextY]
        if (playerTitle && playerTitle.moveable && (!weaponTitle || weaponTitle.turnable)) {

        } else {
          this.state = ENTITY_STATE_ENUM.BLOCKLEFT
          return true
        }
      }
    } else if (inputDirection === CONTROLLER_ENUM.TURNLEFT) {
      let nextX
      let nextY
      if (direction === DIRECTION_ENUM.TOP) {
        nextX = x - 1
        nextY = y - 1
      } else if (direction === DIRECTION_ENUM.BOTTOM) {
        nextX = x + 1
        nextY = y + 1
      } else if (direction === DIRECTION_ENUM.LEFT) {
        nextX = x - 1
        nextY = y + 1
      } else if (direction === DIRECTION_ENUM.RIGHT) {
        nextX = x + 1
        nextY = y - 1
      }

      // door block
      if (((x === doorX && nextY === doorY) || (nextX === doorX && y === doorY) || (nextX === doorX && nextY === doorY)) && doorState !== ENTITY_STATE_ENUM.DEATH) {
        this.state = ENTITY_STATE_ENUM.BLOCKTURNLEFT
        return true
      }

      // enemies block
      for (let i = 0; i < enemies.length; i++) {
        const {x:enemyX, y:enemyY} = enemies[i]
        if ((x === enemyX && nextY === enemyY) || (nextX === enemyX && y === enemyY) || (nextX === enemyX && nextY === enemyY)) {
          this.state = ENTITY_STATE_ENUM.BLOCKTURNLEFT
          return true
        }
      }

      if (
        (!tileInfo[x][nextY] || tileInfo[x][nextY].turnable) &&
        (!tileInfo[nextX][nextY] || tileInfo[nextX][nextY].turnable) &&
        (!tileInfo[nextX][y] || tileInfo[nextX][y].turnable)
      ) {

      } else {
        this.state = ENTITY_STATE_ENUM.BLOCKTURNLEFT
        return true
      }
    }
    return false
  }

  move(inputDirection: CONTROLLER_ENUM) {
    if (inputDirection === CONTROLLER_ENUM.TOP) {
      this.targetY -= 1
      this.isMoving = true
      this.showSmoke(inputDirection)
    } else if (inputDirection === CONTROLLER_ENUM.BOTTOM) {
      this.targetY += 1
      this.isMoving = true
      this.showSmoke(inputDirection)
    } else if (inputDirection === CONTROLLER_ENUM.LEFT) {
      this.targetX -= 1
      this.isMoving = true
      this.showSmoke(inputDirection)
    } else if (inputDirection === CONTROLLER_ENUM.RIGHT) {
      this.targetX += 1
      this.isMoving = true
      this.showSmoke(inputDirection)
    } else if (inputDirection === CONTROLLER_ENUM.TURNLEFT) {
      if (this.direction === DIRECTION_ENUM.TOP) {
        this.direction = DIRECTION_ENUM.LEFT
      } else if (this.direction === DIRECTION_ENUM.LEFT) {
        this.direction = DIRECTION_ENUM.BOTTOM
      } else if (this.direction === DIRECTION_ENUM.BOTTOM) {
        this.direction = DIRECTION_ENUM.RIGHT
      } else if (this.direction === DIRECTION_ENUM.RIGHT) {
        this.direction = DIRECTION_ENUM.TOP
      }
      this.state = ENTITY_STATE_ENUM.TURNLEFT
      EventManager.Instance.emit(EVENT_ENUM.PLAYER_MOVE_END)
    } else if (inputDirection === CONTROLLER_ENUM.TURNRIGHT) {
      if (this.direction === DIRECTION_ENUM.TOP) {
        this.direction = DIRECTION_ENUM.RIGHT
      } else if (this.direction === DIRECTION_ENUM.LEFT) {
        this.direction = DIRECTION_ENUM.TOP
      } else if (this.direction === DIRECTION_ENUM.RIGHT) {
        this.direction = DIRECTION_ENUM.BOTTOM
      } else if (this.direction === DIRECTION_ENUM.BOTTOM) {
        this.direction = DIRECTION_ENUM.LEFT
      }
      this.state = ENTITY_STATE_ENUM.TURNRIGHT
      EventManager.Instance.emit(EVENT_ENUM.PLAYER_MOVE_END)
    }
  }

  showSmoke(type: CONTROLLER_ENUM) {
    EventManager.Instance.emit(EVENT_ENUM.SHOW_SMOKE,this.x ,this.y, type)
  }
}
